
package com.shop.cloud.upms.admin.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.LocalDateTimeUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.log.annotation.SysLog;
import com.shop.cloud.common.security.util.SecurityUtils;
import com.shop.cloud.mall.common.config.MallConfigProperties;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.constant.MallReturnCode;
import com.shop.cloud.mall.common.entity.ShopInfo;
import com.shop.cloud.mall.common.feign.FeignShopInfoService;
import com.shop.cloud.pay.common.dto.AliBaseRequest;
import com.shop.cloud.pay.common.entity.PayConfig;
import com.shop.cloud.upms.admin.service.SysTenantPackageService;
import com.shop.cloud.upms.admin.service.SysTenantService;
import com.shop.cloud.upms.common.entity.SysTenant;
import com.shop.cloud.upms.common.entity.SysTenantPackage;
import com.shop.cloud.upms.common.entity.SysTenantPackageRecharge;
import com.shop.cloud.upms.admin.service.SysTenantPackageRechargeService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 租户套餐充值记录
 *
 * @author 
 * @date 2023-12-27 11:17:30
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/tenantpackagerecharge")
@Tag(description = "tenantpackagerecharge", name = "租户套餐充值记录管理")
public class SysTenantPackageRechargeController {

    private final SysTenantPackageRechargeService sysTenantPackageRechargeService;
    private final com.shop.cloud.pay.common.feign.FeignPayService feignPayService;
    private final SysTenantService sysTenantService;
    private final MallConfigProperties mallConfigProperties;
    private final FeignShopInfoService feignShopInfoService;
    private final SysTenantPackageService sysTenantPackageService;

    /**
     * 租户套餐充值记录分页列表
     * @param page 分页对象
     * @param sysTenantPackageRecharge 租户套餐充值记录
     * @return
     */
    @Operation(summary = "租户套餐充值记录分页列表")
    @GetMapping("/page")
//    @PreAuthorize("@ato.hasAuthority('upms:tenantpackagerecharge:index')")
    public R getPage(Page page, SysTenantPackageRecharge sysTenantPackageRecharge) {
        if(!StrUtil.equals(CommonConstants.USER_TYPE_S, SecurityUtils.getUser().getType())){
            sysTenantPackageRecharge.setTenantId(TenantContextHolder.getTenantId());
            sysTenantPackageRecharge.setIsPay(CommonConstants.YES);
            return R.ok(sysTenantPackageRechargeService.page(page, Wrappers.query(sysTenantPackageRecharge)));
        }else{
            return R.ok(sysTenantPackageRechargeService.page(page, Wrappers.query(sysTenantPackageRecharge)
                    .in("tenant_id", SecurityUtils.getUser().getTenantIds())));
        }
    }

    /**
     * 租户套餐充值记录查询
     * @param id
     * @return R
     */
    @Operation(summary = "租户套餐充值记录查询")
    @GetMapping("/{id}")
//    @PreAuthorize("@ato.hasAuthority('upms:tenantpackagerecharge:get')")
    public R getById(@PathVariable("id") String id) {
        return R.ok(sysTenantPackageRechargeService.getById(id));
    }

    /**
     * 租户套餐充值记录删除
     * @param id
     * @return R
     */
    @Operation(summary = "租户套餐充值记录删除")
    @SysLog("删除租户套餐充值记录")
    @DeleteMapping("/{id}")
    @PreAuthorize("@ato.hasAuthority('upms:tenantpackagerecharge:del')")
    public R removeById(@PathVariable String id) {
        return R.ok(sysTenantPackageRechargeService.removeById(id));
    }

    /**
     * 新增租户套餐充值记录
     * @param sysTenantPackageRecharge
     * @return
     */
    @Operation(summary = "租户套餐充值记录新增")
    @SysLog("新增租户套餐充值记录")
    @PostMapping
//    @PreAuthorize("@ato.hasAuthority('upms:tenantpackagerecharge:add')")
    public R save(@RequestBody SysTenantPackageRecharge sysTenantPackageRecharge) {
        SysTenant sysTenant = sysTenantService.getById(TenantContextHolder.getTenantId());
        if(!sysTenantPackageRecharge.getPackageId().equals(sysTenant.getPackageId())){
            //更换单店模式套餐，校验店铺数量
            SysTenantPackage sysTenantPackage = sysTenantPackageService.getById(sysTenantPackageRecharge.getPackageId());
            if(CommonConstants.MALL_MODE_1.equals(sysTenantPackage.getMallMode())){
                long count = feignShopInfoService.getCount(new ShopInfo(), SecurityConstants.FROM_IN).getData();
                if(count > 1){
                    return R.failed("单店模式只能有一个店铺，请先删除多余店铺");
                }
            }
        }
        sysTenantPackageRecharge.setTenantId(TenantContextHolder.getTenantId());
        sysTenantPackageRecharge.setIsPay(CommonConstants.NO);
        sysTenantPackageRecharge.setTradeNo(IdUtil.getSnowflake(0,0).nextIdStr());
        sysTenantPackageRechargeService.save(sysTenantPackageRecharge);
        return R.ok(sysTenantPackageRecharge);
    }


    /**
     * 统一下单，支付套餐
     * @param sysTenantPackageRecharge
     * @return
     */
    @Operation(summary = "统一下单，支付套餐")
    @SysLog("统一下单，支付套餐")
    @PostMapping("/unified")
//    @PreAuthorize("@ato.hasAuthority('upms:tenantpackagerecharge:add')")
    public R unifiedTenantPackage(HttpServletRequest request, @RequestBody SysTenantPackageRecharge sysTenantPackageRecharge) {
        String paymentType = sysTenantPackageRecharge.getPaymentType();
        if(StrUtil.isBlank(paymentType)){
            return R.failed(MallReturnCode.ERR_70002.getCode(), MallReturnCode.ERR_70002.getMsg());
        }
        sysTenantPackageRecharge = sysTenantPackageRechargeService.getById(sysTenantPackageRecharge.getId());
        //获取支付配置
        TenantContextHolder.setTenantId(CommonConstants.SYSTEM_TENANT_ID);
        R<PayConfig> r = feignPayService.getPayConfigByType(paymentType, SecurityConstants.FROM_IN);
        if(!r.isOk()){
            return R.failed(r.getMsg());
        }
        PayConfig payConfig = r.getData();
        if(payConfig == null){
            return R.failed("支付未配置");
        }
        SysTenant sysTenant = sysTenantService.getById(sysTenantPackageRecharge.getTenantId());
        String body = "支付租户套餐：" + sysTenant.getName();
        body = body.length() > 40 ? body.substring(0,39) : body;
        //微信支付
        if(MallConstants.ORDER_PAYMENT_TYPE_1.equals(paymentType)){
            WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
            wxPayUnifiedOrderRequest.setSubMchId(payConfig.getSpecialMchId());
            wxPayUnifiedOrderRequest.setBody(body);
            wxPayUnifiedOrderRequest.setOutTradeNo(sysTenantPackageRecharge.getTradeNo());
            wxPayUnifiedOrderRequest.setTotalFee(sysTenantPackageRecharge.getPaymentPrice().multiply(new BigDecimal(100)).intValue());
            wxPayUnifiedOrderRequest.setTradeType("NATIVE");//扫码支付
            wxPayUnifiedOrderRequest.setNotifyUrl(mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_UPMS+ "/tenantpackagerecharge/notify-wx/"+sysTenantPackageRecharge.getTenantId());
            wxPayUnifiedOrderRequest.setSpbillCreateIp(request.getRemoteAddr());
            return feignPayService.unifiedOrderWx(wxPayUnifiedOrderRequest, SecurityConstants.FROM_IN);
        }else if(MallConstants.ORDER_PAYMENT_TYPE_2.equals(paymentType)){//支付宝支付
            Map<String, Object> params = new HashMap<>();
            params.put("tradeType","QRCODE");//扫码支付
            params.put("outTradeNo",sysTenantPackageRecharge.getTradeNo());
            params.put("totalAmount",sysTenantPackageRecharge.getPaymentPrice().toString());
            params.put("notifyUrl",mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_UPMS + "/tenantpackagerecharge/notify-ali/" + sysTenantPackageRecharge.getTenantId());
            params.put("subject",body);
            AliBaseRequest aliBaseRequest = new AliBaseRequest();
            aliBaseRequest.setAppAuthToken(payConfig.getSpecialMchId());
            aliBaseRequest.setParams(params);
            return feignPayService.unifiedOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
        }else{
            return R.failed("无此支付类型");
        }
    }

    /**
     * 支付回调（微信）
     * @param xmlData
     * @return
     * @throws WxPayException
     */
    @Operation(summary = "支付回调（微信）")
    @PostMapping("/notify-wx/{tenantId}")
    public String notifyOrderWx(@RequestBody String xmlData, @PathVariable("tenantId") String tenantId) {
        log.info("支付回调（微信）:"+xmlData);
        TenantContextHolder.setTenantId(CommonConstants.SYSTEM_TENANT_ID);//设置租户ID
        R<WxPayOrderNotifyResult> r = feignPayService.notifyOrderWx(xmlData, SecurityConstants.FROM_IN);
        TenantContextHolder.setTenantId(tenantId);//设置租户ID
        if(r.isOk()){
            WxPayOrderNotifyResult notifyResult = r.getData();
            SysTenantPackageRecharge sysTenantPackageRecharge = sysTenantPackageRechargeService.getOne(Wrappers.<SysTenantPackageRecharge>lambdaQuery()
                    .eq(SysTenantPackageRecharge::getTradeNo,notifyResult.getOutTradeNo()));
            if(sysTenantPackageRecharge != null){
                if(sysTenantPackageRecharge.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == notifyResult.getTotalFee()){
                    String timeEnd = notifyResult.getTimeEnd();
                    LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
                    sysTenantPackageRecharge.setPaymentTime(paymentTime);
                    sysTenantPackageRecharge.setTransactionId(notifyResult.getTransactionId());
                    sysTenantPackageRecharge.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_1);
                    sysTenantPackageRechargeService.notifyTenantPackageRecharge(sysTenantPackageRecharge);
                    return WxPayNotifyResponse.success("成功");
                }else{
                    return WxPayNotifyResponse.fail("付款金额与订单金额不等");
                }
            }else{
                return WxPayNotifyResponse.fail("无此订单");
            }
        }else{
            return WxPayNotifyResponse.fail(r.getMsg());
        }
    }

    /**
     * 支付回调（支付宝）
     * @param request
     * @return
     * @throws
     */
    @Operation(summary = "支付回调（支付宝）")
    @ResponseBody
    @PostMapping("/notify-ali/{tenantId}")
    public String notifyOrderAli(HttpServletRequest request, @PathVariable("tenantId") String tenantId) {
        log.info("支付回调（支付宝）");
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        String appId = request.getParameter("app_id");
        if(StrUtil.isBlank(appId)){
            return "appId不能为空";
        }
        TenantContextHolder.setTenantId(tenantId);//设置租户ID
        SysTenantPackageRecharge sysTenantPackageRecharge = sysTenantPackageRechargeService.getOne(Wrappers.<SysTenantPackageRecharge>lambdaQuery()
                .eq(SysTenantPackageRecharge::getTradeNo,request.getParameter("out_trade_no")));
        if(sysTenantPackageRecharge == null){
            log.error("无此订单out_trade_no："+request.getParameter("out_trade_no"));
            return "无此订单";
        }
        if(sysTenantPackageRecharge.getPaymentPrice().compareTo(new BigDecimal(request.getParameter("total_amount"))) == 0){
            LocalDateTime paymentTime = LocalDateTimeUtils.parse(request.getParameter("gmt_payment"));
            sysTenantPackageRecharge.setPaymentTime(paymentTime);
            sysTenantPackageRecharge.setTransactionId(request.getParameter("trade_no"));
            sysTenantPackageRecharge.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_2);
            sysTenantPackageRechargeService.notifyTenantPackageRecharge(sysTenantPackageRecharge);
            log.info("支付回调（支付宝）success");
            return "success";
        }else{
            log.error("付款金额与订单金额不等out_trade_no："+request.getParameter("out_trade_no"));
            return "付款金额与订单金额不等";
        }

    }
}
